Rectangle Cutting
題目
給兩數 ,代表你有一個大小是 的長方形,現在你可以切一刀把他切成兩個長方形,問最少要切幾刀才能全部切成正方形。
輸入
共一行,兩個數字,代表 和 。
輸出
共一個字,代表最少需要幾刀。
範例測資
Input :
3 5
Output :
3
切成 和 ,第二刀將 切成 和 ,第三刀將 切成兩個 。
o o o|o o
|
o o o|o o
|---
o o o|o|o
想法 1:貪心
每次根據短邊去切出最大的正方形,切完只會剩下一個長方形要切。
但是如果輸入是5 6
,貪心會切出 和 個 ,共五刀。
o o o o o|o
|-
o o o o o|o
|-
o o o o o|o
|-
o o o o o|o
|-
o o o o o|o
最佳解則是第一刀切成 和 ,再切成兩個 和 個 ,共四刀。
o o o|o o o
|
o o o|o o o
|
o o o|o o o
-----------
o o|o o|o o
| |
o o|o o|o o
想法 2:試試看全部可能
既然貪心失敗了,或者根本沒去考慮貪心,就先照著題目做做看,我們可以枚舉這一刀要切在哪,並且全部試試看,可以橫著切或直著切。 假設現在是一個 的長方形且他的答案是 ,若 答案就是 ,否則答案是橫著切,也就是 ,或是直著切, ,所有可能之中最小的,所以這其實是一題二維 dp ,枚舉所有可能的長寬,空間複雜度是 ,時間複雜度是枚舉不同大小的長方形,以及橫著或直著切在哪,因此時間複雜度是 ,省略常數就是 。
範例程式碼
C++ 範例
#include <bits/stdc++.h>
using namespace std;
#define MAX 1 << 30
int dp[505][505];
int main(){
int a, b;
cin >> a >> b;
for(int i = 1; i <= a; ++i) {
for(int j = 1; j <= b; ++j) {
if(i == j) {
dp[i][j] = 0;
continue;
}
dp[i][j] = MAX;
for(int k = 1;k < i; ++k) dp[i][j] = min(dp[i][j], dp[k][j] + dp[i - k][j] + 1);
for(int k = 1;k < j; ++k) dp[i][j] = min(dp[i][j], dp[i][k] + dp[i][j - k] + 1);
}
}
cout << dp[a][b];
}